<?php

namespace App\Lib\file;

use App\Exceptions\BaseException;
use App\Exceptions\lin\LinException;

abstract class File
{
    //被允许的文件类型列表
    protected $includes;
    //不被允许的文件类型列表
    protected $excludes;
    //单个文件的最大字节数
    protected $singleLimit;
    //多个文件的最大数量
    protected $totalLimit;
    //文件上传的最大数量
    protected $nums;
    //文件存储目录
    protected $storeDir;
    //文件存储对象
    protected $files;

    public function __construct($files, $config = [])
    {
        //是否传入数据
        $this->files = $files;
        $this->includes = [];
        $this->excludes = [];
        $this->singleLimit = 0;
        $this->totalLimit = 0;
        $this->nums = 0;
        $this->storeDir = '';
        //加载配置
        $this->loadConfig($config);
        //是否有文件上传
        $this->verify();
    }

    abstract public function upload();

    protected function loadConfig(array $config)
    {
        $defaultConfig = Config('filesystems.disks.uploads');
        $this->includes = $config['include'] ?? $defaultConfig['include'];
        $this->excludes = $config['exclude'] ?? $defaultConfig['exclude'];
        $this->singleLimit = $config['single_limit'] ?? $defaultConfig['single_limit'];
        $this->totalLimit = $config['total_limit'] ?? $defaultConfig['total_limit'];
        $this->nums = $config['nums'] ?? $defaultConfig['nums'];
        $this->storeDir = $config['store_dir'] ?? $defaultConfig['store_dir'];
    }

    protected function verify()
    {
        if (!$this->files) {
            throw new LinException(10033);
        }
        $this->allowdFile();
        $this->allowedFileSize();
    }

    protected function allowdFile()
    {
        if ((!empty($this->includes) && !empty($this->exclude)) || !empty($this->includes)) {
            foreach ($this->files as $v) {
                $fileName = $v->getClientOriginalName();
                if (!strpos($fileName, '.') || !in_array($v->getClientOriginalExtension(), $this->includes)) {
                    throw new LinException(10130, ['ext' => $v->getClientOriginalExtension()]);
                }
            }
        } else if (!empty($this->excludes) && empty($this->includes)) {
            foreach ($this->files as $v) {
                $fileName = $v->getClientOriginalName();
                if (!strpos($fileName, '.') || in_array($v->getClientOriginalExtension(), $this->excludes)) {
                    throw new LinException(10130, ['ext' => $v->getClientOriginalExtension()]);
                }
            }
        }
        return true;
    }

    protected function allowedFileSize()
    {
        $fileCount = count($this->files);
        if ($fileCount > $this->nums) {
            throw new LinException(10121, ['num' => $this->nums]);
        }
        $totalSize = 0;
        foreach ($this->files as $k => $file) {
            $fileSize = $file->getSize();
            if ($fileSize > $this->singleLimit) {
                throw new LinException(10110, ['name' => $file->getClientOriginalExtension(), 'size' => $this->singleLimit]);
            }
            $totalSize += $fileSize;
        }
        if ($totalSize > $this->totalLimit) {
            throw new LinException(10111, ['size' => $this->totalLimit]);
        }
    }
}
